package com.singfan.common.util;

import com.singfan.common.SingFanException;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * JavaBean相关工具类
 * Author: HanSongHe
 * Date: 2015-07-27 12:01
 * Desc: JavaBean常用的一些反射操作
 */
public class BeanUtil {
    /**
     * 获取JavaBean中所有Field的列表（包括所有父类中的Filed，但JDK中的父类除外）
     * @param beanClass JavaBean的类信息
     * @return JavaBean中所有Field的列表
     */
    public static List<Field> getBeanFieldList(Class beanClass){
        List<Field> result = new ArrayList<>();

        Field[] filedArr = beanClass.getDeclaredFields();
        if (filedArr.length > 0){
            List<Field> selfFieldList = Arrays.asList(filedArr);
            result.addAll(selfFieldList);

            Class fatherClass = beanClass.getSuperclass();
            if(fatherClass != null && !fatherClass.getName().contains("java.")){
                List<Field> superFieldList = getBeanFieldList(fatherClass);
                result.addAll(superFieldList);
            }
        }

        return result;
    }

    /**
     * 动态调用set方法设置bean对象字段的值
     *
     * @param beanObject bean对象
     * @param fieldName 字段名
     * @param fieldValue 字段值
     */
    public static void setBeanFieldValue(Object beanObject, String fieldName, Object fieldValue) {
        if (beanObject != null){
            if (!StringUtil.isNullOrEmpty(fieldName)){
                try{
                    String setMethodName = generateSetMethodName(fieldName);
                    Method setMethod = null;
                    Method[] methodArr = beanObject.getClass().getMethods();
                    if (methodArr != null && methodArr.length > 0){
                        for(Method method : methodArr){
                            if(method.getName().equals(setMethodName)){
                                setMethod = method;
                                break;
                            }
                        }
                    }

                    if (setMethod != null){
                        setMethod.invoke(beanObject,fieldValue);
                    }
                    else{
                        throw new SingFanException(String.format("BeanUtil.setBeanFieldValue() error: %s has not exist method(%s) for field(%s) !", beanObject.getClass().getName(), setMethodName, fieldName));
                    }
                }
                catch (Exception ex){
                    throw new SingFanException(String.format("BeanUtil.setBeanFieldValue() error: %s !", ex.getMessage()), ex);
                }
            }
            else {
                throw new SingFanException("BeanUtil.setBeanFieldValue() error: fieldName is null or empty !");
            }
        }
        else {
            throw new SingFanException("BeanUtil.setBeanFieldValue() error: beanObject is null !");
        }
    }

    /**
     * 动态调用get方法获取bean对象字段的值
     *
     * @param beanObject bean对象
     * @param fieldName 字段名
     * @return bean对象字段的值
     */
    public static Object getBeanFieldValue(Object beanObject, String fieldName) {
        if (beanObject != null){
            if (!StringUtil.isNullOrEmpty(fieldName)){
                try{
                    Method getMethod = null;

                    String getMethodName = generateGetMethodName(fieldName);
                    String isMethodName = generateIsMethodName(fieldName);
                    Method[] methodArr = beanObject.getClass().getMethods();
                    if (methodArr != null && methodArr.length > 0){
                        for(Method method : methodArr){
                            if(method.getName().equals(getMethodName) || method.getName().equals(isMethodName)){
                                getMethod = method;
                                break;
                            }
                        }
                    }

                    if (getMethod != null) {
                        return getMethod.invoke(beanObject);
                    }
                    else {
                        throw new SingFanException(String.format("BeanUtil.getBeanFieldValue() error: %s has not exist method(%s) for field(%s) !", beanObject.getClass().getName(), getMethodName, fieldName));
                    }
                }
                catch (Exception ex){
                    throw new SingFanException(ex.getMessage(), ex);
                }
            }
            else {
                throw new SingFanException("BeanUtil.getBeanFieldValue() error: fieldName is null or empty !");
            }
        }
        else {
            throw new SingFanException("BeanUtil.getBeanFieldValue() error: beanObject is null !");
        }
    }

    /**
     * 是否为jdk自带的类型
     * @param field 要判断的字段
     * @return true：是  false：不是
     */
    private static boolean isJdkType(Field field){
        boolean result = false;

        String typeName = field.getType().getName();
        if(typeName.startsWith("java.")){
            result = true;
        }
        else if(typeName.equals("int")){
            result = true;
        }
        else if(typeName.equals("short")){
            result = true;
        }
        else if(typeName.equals("char")){
            result = true;
        }
        else if(typeName.equals("long")){
            result = true;
        }
        else if(typeName.equals("float")){
            result = true;
        }
        else if(typeName.equals("double")){
            result = true;
        }
        else if(typeName.equals("byte")){
            result = true;
        }
        else if(typeName.equals("boolean")){
            result = true;
        }

        return result;
    }

    /**
     * 生成boolean类型字段的is方法名
     *
     * @param fieldName 字段名
     * @return 字段的is方法名
     */
    private static String generateIsMethodName(String fieldName){
        String InitialCapitalFieldName = StringUtil.setInitialCapital(fieldName);
        return "is" + InitialCapitalFieldName;
    }

    /**
     * 生成字段的get方法名
     *
     * @param fieldName 字段名
     * @return 字段的get方法名
     */
    private static String generateGetMethodName(String fieldName){
        String InitialCapitalFieldName = StringUtil.setInitialCapital(fieldName);
        return "get" + InitialCapitalFieldName;
    }

    /**
     * 生成字段的set方法名
     *
     * @param fieldName 字段名
     * @return 字段的set方法名
     */
    private static String generateSetMethodName(String fieldName){
        String InitialCapitalFieldName = StringUtil.setInitialCapital(fieldName);
        return "set" + InitialCapitalFieldName;
    }
}
